const path = require('path')
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const defaultSettings = require('./src/config/settings.js')

const port = 3100
const proxy = true
const userCDN = false
const name = defaultSettings.title || 'Web'
const isDev = process.env.NODE_ENV === 'development'
const isProduction = process.env.NODE_ENV === 'production'
const isLocalBuild = process.env.IS_LOCAL_BUILD === 'isLocalBuild' // 预发布环境

// 是否使用gzip
const productionGzip = true
// 需要gzip压缩的文件后缀
const productionGzipExtensions = ['js', 'css']

function resolve (dir) {
  return path.join(__dirname, dir)
}

// cdn预加载使用
const externals = {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'vuex': 'Vuex',
  'axios': 'axios',
  'element-ui': 'ELEMENT',
  'js-cookie': 'Cookies'
}

const cdn = {
  // 开发环境
  dev: {
    css: [
      // 'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
    ],
    js: []
  },
  // 生产环境
  build: {
    css: [
      'https://unpkg.com/normalize.css/normalize.css',
      'https://unpkg.com/element-ui/lib/theme-chalk/index.css'
    ],
    js: [
      'https://cdn.bootcss.com/vue/2.5.22/vue.min.js',
      'https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js',
      'https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js',
      'https://cdn.bootcss.com/axios/0.18.0/axios.min.js',
      'https://cdn.bootcss.com/js-cookie/2.2.0/js.cookie.min.js',
      'https://unpkg.com/element-ui/lib/index.js'
    ]
  }
}

module.exports = {
  publicPath: isProduction ? '/' : '/', // 添加URL前缀
  outputDir: 'dist',
  assetsDir: 'assets',
  filenameHashing: true,
  lintOnSave: isDev,
  runtimeCompiler: false,
  transpileDependencies: [],
  productionSourceMap: false,
  devServer: {
    open: true,
    port,
    overlay: {
      warnings: false,
      errors: true
    },
    https: false,
    hotOnly: false,
    proxy: !proxy ? null : {
      // change xxx-api/login => mock/login
      // detail: https://cli.vuejs.org/config/#devserver-proxy
      [process.env.VUE_APP_BASE_API]: {
        target: `http://localhost:${port}`,
        changeOrigin: true,
        pathRewrite: {
          ['^' + process.env.VUE_APP_BASE_API]: '/mock'
        }
      }
    },
    after: !proxy ? () => {
    } : require('./.mock-server/index.js'),
    /**
     * 关闭host check，方便使用ngrok之类的内网转发工具
     * 如果开发者使用了代理，或在开发环境中不 care 这些安全问题，该设置应该删除
     */
    disableHostCheck: isDev
  },
  configureWebpack: () => {
    // 修改webpack config, 使其不打包externals下的资源
    const myConfig = { name }
    if (isProduction) {
      // 1. 生产环境npm包转CDN
      if (userCDN) myConfig.externals = externals

      myConfig.plugins = []
      // 2. 构建时开启gzip，降低服务器压缩对CPU资源的占用，服务器也要相应开启gzip
      productionGzip && myConfig.plugins.push(
        new CompressionWebpackPlugin({
          test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
          threshold: 8192,
          minRatio: 0.8
        })
      )
    }

    return myConfig
  },
  chainWebpack: (config) => {
    if (userCDN) {
      config.plugin('html').tap(args => {
        if (isProduction) {
          args[0].cdn = cdn.build
        }
        if (isDev) {
          args[0].cdn = cdn.dev
        }
        return args
      })
    }

    config.optimization.minimizer('terser').tap((args) => {
      args[0].terserOptions.compress.drop_console = true
      return args
    })

    /**
     * 删除懒加载模块的prefetch，降低带宽压力
     * https://cli.vuejs.org/zh/guide/html-and-static-assets.html#prefetch
     * 而且预渲染时生成的prefetch标签是modern版本的，低版本浏览器是不需要的
     */
    config.plugins.delete('prefetch')
    // config.plugins.delete('preload');

    const imgLoaderConfig = {
      mozjpeg: {
        progressive: true,
        quality: 65
      },
      optipng: {
        enabled: false // false will disable optipng
      },
      pngquant: {
        quality: [0.65, 0.90],
        speed: 4
      },
      gifsicle: {
        interlaced: false
      },
      webp: {
        quality: 75 // the webp option will enable WEBP
      }
    }

    config.resolve.alias
      .set('@assets', resolve('src/assets'))
      .set('@pages', resolve('src/pages'))
      .set('@components', resolve('src/components'))
      .set('@utils', resolve('src/utils'))

    config.module
      .rule('svg')
      .exclude.add(resolve('src/icons'))
      .end()
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options(Object.assign({}, imgLoaderConfig))

    config.module
      .rule('images')
      .use('image-webpack-loader')
      .loader('image-webpack-loader')
      .options(Object.assign({}, imgLoaderConfig))

    config.module
      .rule('eslint')
      .exclude.add(resolve('src/libs'))
      .end()

    config.module
      .rule('svg2')
      .test(/\.svg$/)
      .include
      .add(resolve('src/icons'))
      .end()
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })
      .end()

    // https://webpack.js.org/configuration/devtool/#development
    config
      .when(isDev,
        config => config.devtool('cheap-source-map')
      )

    // 代码分离
    /*
     config
     .when(process.env.NODE_ENV !== "development",
     config => {
     config
     .plugin('ScriptExtHtmlWebpackPlugin')
     .after('html')
     .use('script-ext-html-webpack-plugin', [{
     // `runtime` must same as runtimeChunk name. default is `runtime`
     inline: /runtime\..*\.js$/
     }])
     .end()
     config
     .optimization.splitChunks({
     chunks: 'all',
     cacheGroups: {
     vendor: {
     name: 'chunk-vendor',
     test: /[\\/]node_modules[\\/]/,
     priority: 10,
     chunks: 'initial' // only package third parties that are initially dependent
     },
     elementUI: {
     name: 'chunk-elementUI', // split elementUI into a single package
     priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
     test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
     },
     commons: {
     name: 'chunk-commons',
     test: resolve('src/components'), // can customize your rules
     minChunks: 3, //  minimum common number
     priority: 5,
     reuseExistingChunk: true
     }
     }
     })
     config.optimization.runtimeChunk('single')

     }
     );
     */

    /* 添加代码混淆 webpack-obfuscator */
    if (isProduction) {
      config.module
        .rule('obfuscator')
        .post()
        .enforce('post')
        .test(/key\.js$/)
        .include
        .add(resolve('src/utils'))
        .end()
        .use('obfuscator-loader')
        .loader('obfuscator-loader')
        .options({
          compact: true, // 压缩代码
          controlFlowFlattening: false, // 是否启用控制流扁平化(降低1.5倍的运行速度)
          deadCodeInjection: false, // 随机的死代码块(增加了混淆代码的大小)
          debugProtection: false, // 此选项几乎不可能使用开发者工具的控制台选项卡
          debugProtectionInterval: false, // 如果选中，则会在“控制台”选项卡上使用间隔强制调试模式，从而更难使用“开发人员工具”的其他功能。
          disableConsoleOutput: true, // 通过用空函数替换它们来禁用console.log，console.info，console.error和console.warn。这使得调试器的使用更加困难。
          identifierNamesGenerator: 'hexadecimal', // 标识符的混淆方式 hexadecimal(十六进制) mangled(短标识符)
          log: false,
          renameGlobals: false, // 是否启用全局变量和函数名称的混淆
          rotateStringArray: true, // 通过固定和随机（在代码混淆时生成）的位置移动数组。这使得将删除的字符串的顺序与其原始位置相匹配变得更加困难。如果原始源代码不小，建议使用此选项，因为辅助函数可以引起注意。
          selfDefending: false, // 混淆后的代码,不能使用代码美化,同时需要配置 compat:true; 很容易报错 Maximum call stack size exceed.
          stringArray: true, // 删除字符串文字并将它们放在一个特殊的数组中
          stringArrayEncoding: false,
          stringArrayThreshold: 0.75,
          unicodeEscapeSequence: false
        })
    }

    config
      .module
      .rule('unicode')
      .test(/\.(js)?$/)
      .include
      .add(resolve('src'))
      .end()
      .use('unicode-loader')
      .loader('unicode-loader')
  },
  css: {
    requireModuleExtension: true,
    extract: true,
    sourceMap: false
  },
  parallel: require('os').cpus().length > 1
}
